#include <QtNetwork/QtNetwork>
#include <QtNetwork/QTcpSocket>
#include "queryhistorybilldataaccess.h"
#include "common/dynobjectfactory.h"
#include "common/jinstream.h"
#include "control/bankexception.h"

#define HISTORY_BILL    0x09
#define BUF_SIZE    1024

QueryHistoryBillDataAccess::QueryHistoryBillDataAccess()
    : maxPageNum_(-1),maxPageItemsInx_(0),lastPageItemsNum_(0)
{
    data_ = new char[BUF_SIZE];
}

QueryHistoryBillDataAccess::~QueryHistoryBillDataAccess()
{
    delete []data_;
}

//数据进行请求发送
bool QueryHistoryBillDataAccess::requestData(QSharedPointer<QTcpSocket> &cliPipe,
                                             map<QString, QString> &rDataMap)
{
    //这里也可以针对查询做进一步的检查如果还有缓存就直接返回缓存的数据
    //这里也可以针对查询做进一步的检查如果还有缓
    //存就直接返回缓存的数据
    //首先要记录一个已查询出结果的最大page数量
    //然后就是每次与其比较，从0开始
    //需要根据当前的页号计算出该页填满对应的最大
    //索引以及该页的元素索引数
    //首先可能不定的是最后一页索引，其余页索引应
    //该都是一样的（业务是这样假设的）
    //然后是对该页的最大索引的推算
    map<QString,QString>::const_iterator it;
    //page
    it = rDataMap.find("page");
    if(it == rDataMap.end()) {
        rDataMap.insert(make_pair("errorMsg",
            "page name can't be found!"));
        return false;
    }
    qint32 page = it->second.toInt();
    if(page < maxPageNum_) {
        //这里表明可以查询缓存
        //除去最后一页不定长，之前的页一定都是定长的
        quint32 curPageItemsInx = (maxPageItemsInx_ - lastPageItemsNum_) /
                (((maxPageNum_ - 1) == 0) ? 1 : (maxPageNum_ - 1));
        quint32 curMaxPageItems = maxPageItemsInx_ - lastPageItemsNum_ -
                (maxPageNum_ - 1 - page) * curPageItemsInx;
        //计算得到当前页的数量
        QString resItemsPerCurPageStr;
        resItemsPerCurPageStr.sprintf("%d",curPageItemsInx);
        it = rDataMap.find("resItemsPerCurPage");
        if(it != rDataMap.end()) {
            rDataMap.erase("resItemsPerCurPage");
        }
        rDataMap.insert(make_pair("resItemsPerCurPage",resItemsPerCurPageStr));
        //计算得到总的元素数量
        QString maxPageInxStr;
        maxPageInxStr.sprintf("%d",curMaxPageItems);
        it = rDataMap.find("resMaxPageItemsInx");
        if(it != rDataMap.end()) {
            rDataMap.erase("resMaxPageItemsInx");
        }
        rDataMap.insert(make_pair("resMaxPageItemsInx",maxPageInxStr));
        return true;
    }
    // 包头命令
    quint16 cmd = HISTORY_BILL;
    jos_.Clear();
    jos_ << cmd;
    // 预留两个字节包头len（包体+包尾长度）
    size_t lengthPos = jos_.Length();
    jos_.Skip(2);
    //page
    jos_ << page;
    //startDate
    it = rDataMap.find("startDate");
    if(it == rDataMap.end()) {
        rDataMap.insert(make_pair("errorMsg",
                "startDate name can't be found!"));
        return false;
    }
    QString startDateStr = it->second;
    const char *startDateData = (const char *)startDateStr.toLocal8Bit();
    jos_.WriteBytes(startDateData,startDateStr.length());
    //endDate
    it = rDataMap.find("endDate");
    if(it == rDataMap.end()) {
        rDataMap.insert(make_pair("errorMsg",
                "endDate name can't be found!"));
        return false;
    }
    QString endDateStr = it->second;
    const char *endDateData = (const char *)endDateStr.toLocal8Bit();
    jos_.WriteBytes(endDateData,endDateStr.length());
    // 包头len
    size_t tailPos = jos_.Length();
    jos_.Reposition(lengthPos);
    jos_<< static_cast<uint16>(tailPos + 8 - sizeof(RequestHead)); // 包体长度 + 包尾长度
    // 包尾
    jos_.Reposition(tailPos);
    // 计算包尾
    generatePackTailMd5(cmd);
    cliPipe->write(jos_.Data(), jos_.Length());
    if(!cliPipe->waitForBytesWritten(3000)) {
        throw BankException(cliPipe->errorString().toLocal8Bit());
    }
    return true;
}

//对数据进行响应
bool QueryHistoryBillDataAccess::responseData(QSharedPointer<QTcpSocket> &cliPipe,
                                                map<QString, QString> &rDataMap)
{
    //这里也可以针对查询做进一步的检查如果还有缓存就直接返回缓存的数据
    //或者在请求的时候就设置好标志进行检查
    map<QString,QString>::const_iterator it;
    //page
    it = rDataMap.find("page");
    if(it == rDataMap.end()) {
        rDataMap.insert(make_pair("errorMsg",
            "page name can't be found!"));
        return false;
    }
    qint32 page = it->second.toInt();
    if(page < maxPageNum_) {
        return true;//直接取缓冲，没必要查询了
    }
    //没有这里再做查询
    //对一些变量进行提取，因为这里会多次读取
    uint16 cnt;
    uint16 seq;
    int16 error_code;
    char error_msg[31];

    char transDate[20] = {0};
    char accountId[7] = {0};
    char otherAccountId[7] = {0};
    string money,abstractName,balance;
    quint32 total;
    QString resStr;
    QString resValStr;
    quint32 itemsCount = 0;
    quint32 itemsPerCurPage = 0;
    //有一些变量只需要一次就够了
    bool firstFlag = true;
LOOP:
    //需要循环的代码
    memset(data_,0,BUF_SIZE);
    if(!cliPipe->waitForReadyRead(3000)) {
        throw BankException(cliPipe->errorString().toLocal8Bit());
    }
    dataLen_ = cliPipe->read(data_,BUF_SIZE);
    //这里应该执行接收包的包验证
    if(!checkData()) {
        throw BankException("data check sum error!");
    }
    JInStream jis((const char*)data_, dataLen_);
    // 跳过cmd、len
    jis.Skip(4);
    jis >> cnt >> seq >> error_code;
    if(firstFlag) {
        itemsPerCurPage = cnt;
        firstFlag = false;
    }
    memset(error_msg,0,sizeof(error_msg));
    jis.ReadBytes(error_msg, 30);
    if(0 != error_code) {
        rDataMap.insert(make_pair("errorMsg",error_msg));
        return false;
    }
    //需要注意服务器返回来的数量和客户端规定的数量可能会有差距
    //循环接收条目数据
    //cnt是总数
    memset(transDate,0,sizeof(transDate));
    memset(accountId,0,sizeof(accountId));
    memset(otherAccountId,0,sizeof(otherAccountId));
    jis.ReadBytes(transDate,sizeof(transDate) - 1);
    jis.ReadBytes(accountId,sizeof(accountId) - 1);
    jis.ReadBytes(otherAccountId,sizeof(otherAccountId) - 1);
    money.clear();abstractName.clear();balance.clear();
    jis >> money >> abstractName >> balance >> total;
    //构造数据进行插入
    //直接在最大的索引上进行增加
    //到这里来一定是最后一页
    //要么是增量要么是当前最大页刷新
    //如果是其它页都会从缓存中取数据
    qint32 inx = maxPageItemsInx_ -
        ((page == maxPageNum_) ? lastPageItemsNum_ : 0) + itemsCount;
    //然后进行插入
    resStr.clear();
    resStr.sprintf("resInx%d",inx);
    it = rDataMap.find(resStr);
    if(it != rDataMap.end()) {
        rDataMap.erase(resStr);
    }
    resValStr.clear();
    resValStr.sprintf("%d",inx);
    rDataMap.insert(make_pair(resStr,resValStr));
    //resTransactionDate
    resStr.clear();
    resStr.sprintf("resTransactionDate%d",inx);
    it = rDataMap.find(resStr);
    if(it != rDataMap.end()) {
        rDataMap.erase(resStr);
    }
    rDataMap.insert(make_pair(resStr,QString(transDate)));
    //resOwnerAccountId
    resStr.clear();
    resStr.sprintf("resOwnerAccountId%d",inx);
    it = rDataMap.find(resStr);
    if(it != rDataMap.end()) {
        rDataMap.erase(resStr);
    }
    rDataMap.insert(make_pair(resStr,QString(accountId)));
    //resOtherAccountId
    resStr.clear();
    resStr.sprintf("resOtherAccountId%d",inx);
    it = rDataMap.find(resStr);
    if(it != rDataMap.end()) {
        rDataMap.erase(resStr);
    }
    rDataMap.insert(make_pair(resStr,QString(otherAccountId)));
    //resSummary
    resStr.clear();
    resStr.sprintf("resSummary%d",inx);
    it = rDataMap.find(resStr);
    if(it != rDataMap.end()) {
        rDataMap.erase(resStr);
    }
    rDataMap.insert(make_pair(resStr,QString(abstractName.c_str())));
    //resTransactionCash
    resStr.clear();
    resStr.sprintf("resTransactionCash%d",inx);
    it = rDataMap.find(resStr);
    if(it != rDataMap.end()) {
        rDataMap.erase(resStr);
    }
    rDataMap.insert(make_pair(resStr,QString(money.c_str())));
    //resBalance
    resStr.clear();
    resStr.sprintf("resBalance%d",inx);
    it = rDataMap.find(resStr);
    if(it != rDataMap.end()) {
        rDataMap.erase(resStr);
    }
    rDataMap.insert(make_pair(resStr,QString(balance.c_str())));
    //这个要加1
    itemsCount++;
    if (seq != cnt - 1)
        goto LOOP;
    //其它一些统计变量更新
    //计算得到当前页的数量
    QString resItemsPerCurPageStr;
    resItemsPerCurPageStr.sprintf("%d",itemsPerCurPage);
    it = rDataMap.find("resItemsPerCurPage");
    if(it != rDataMap.end()) {
        rDataMap.erase("resItemsPerCurPage");
    }
    rDataMap.insert(make_pair("resItemsPerCurPage",resItemsPerCurPageStr));
    //page运行到这里来说明都是最后一页
    if(page > maxPageNum_) {
        maxPageNum_ = page;
        maxPageItemsInx_ += cnt;
    } else if(page == maxPageNum_) {
        //计算得到总的元素数量
        //有增量索引数才应该增加
        //最后一页要注意有无数据更新的情况，所以要重新对最大值进行计算
        maxPageItemsInx_ = maxPageItemsInx_ - lastPageItemsNum_ + cnt;
    }
    QString maxPageNumStr;
    maxPageNumStr.sprintf("%d",maxPageNum_);
    it = rDataMap.find("resMaxPageNum");
    if(it != rDataMap.end()) {
        rDataMap.erase("resMaxPageNum");
    }
    rDataMap.insert(make_pair("resMaxPageNum",maxPageNumStr));
    //更新下最后一页
    lastPageItemsNum_ = cnt;
    QString maxPageItemsInxStr;
    maxPageItemsInxStr.sprintf("%d",maxPageItemsInx_);
    it = rDataMap.find("resMaxPageItemsInx");
    if(it != rDataMap.end()) {
        rDataMap.erase("resMaxPageItemsInx");
    }
    rDataMap.insert(make_pair("resMaxPageItemsInx",maxPageItemsInxStr));
    return true;
}

REGISTER_CLASS(QueryHistoryBillDataAccess);
